package com.hqumath.androidnative.tools;

import android.media.MediaCodecInfo;
import android.media.MediaCodecList;

import com.hqumath.androidnative.utils.ByteUtil;
import com.hqumath.androidnative.utils.LogUtil;

public class VideoTool {
    public static final String TAG = "VideoTool";
    public static String softDecoder = "! decodebin3 ! videoconvert";//默认软解 高通软解H265存在问题，decodebin改decodebin3
    public static byte[] NALUStartCode = {0b00000000, 0b00000000, 0b00000000, 0b00000001};//H265 NALU单元开始标识
    public static int RtpSnLast;//RTP报文序列号

    /**
     * 手机解码器
     */
    public static String getDecoder(String endcoding) {
        String decoder;
        try {
            // 获取所有支持编解码器数量
            int numCodecs = MediaCodecList.getCodecCount();
            // 打印解码器
            /*for (int i = 0; i < numCodecs; i++) {
                MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
                if (!codecInfo.isEncoder())
                    LogUtil.d(TAG", "---" + codecInfo.getName());
            }*/
            for (int i = 0; i < numCodecs; i++) {
                // 编解码器相关性信息存储在MediaCodecInfo中
                MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
                // 判断是否为编码器
                if (!codecInfo.isEncoder()) {
                    if ("H265".equals(endcoding) || "h265".equals(endcoding)) {
                        //高通
                        if ("OMX.qcom.video.decoder.hevc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxqcomvideodecoderhevc";
                            return decoder;
                        }
                        //联发科
                        if ("OMX.MTK.VIDEO.DECODER.HEVC".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxmtkvideodecoderhevc";
                            return decoder;
                        }
                        //海思
                        if ("OMX.hisi.video.decoder.hevc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxhisivideodecoderhevc";
                            return decoder;
                        }
                        //全志, H40机顶盒
                        if ("OMX.allwinner.video.decoder.hevc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxallwinnervideodecoderhevc";
                            return decoder;
                        }
                        //瑞芯微, H50 T98机顶盒
                        if ("OMX.rk.video_decoder.hevc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxrkvideodecoderhevc";
                            return decoder;
                        }
                        //晶晨 小米box4机顶盒
                        if ("OMX.amlogic.hevc.decoder.awesome".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxamlogichevcdecoderawesome";
                            return decoder;
                        }
                        //海思上一代 荣耀6X麒麟655
                        if ("OMX.IMG.MSVDX.Decoder.HEVC".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omximgmsvdxdecoderhevc";
                            return decoder;
                        }
                        //猎户座Exynos VIVO X30,VIVO S6
                        if ("OMX.Exynos.HEVC.Decoder".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxexynoshevcdecoder";
                            return decoder;
                        }
                        //猎户座上一代 三星GALAXY S6 Edge+
                        if ("OMX.Exynos.hevc.dec".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxexynoshevcdec";
                            return decoder;
                        }
                    } else if ("H264".equals(endcoding) || "h264".equals(endcoding)) {
                        //高通
                        if ("OMX.qcom.video.decoder.avc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxqcomvideodecoderavc";
                            return decoder;
                        }
                        //联发科
                        if ("OMX.MTK.VIDEO.DECODER.AVC".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxmtkvideodecoderavc";
                            return decoder;
                        }
                        //海思
                        if ("OMX.hisi.video.decoder.avc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxhisivideodecoderavc";
                            return decoder;
                        }
                        //全志, H40机顶盒
                        if ("OMX.allwinner.video.decoder.avc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxallwinnervideodecoderavc";
                            return decoder;
                        }
                        //瑞芯微, H50 T98机顶盒
                        if ("OMX.rk.video_decoder.avc".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxrkvideodecoderavc";
                            return decoder;
                        }
                        //晶晨 小米box4机顶盒
                        if ("OMX.amlogic.avc.decoder.awesome".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxamlogicavcdecoderawesome";
                            return decoder;
                        }
                        //海思上一代 荣耀6X麒麟655 华为P9麒麟955
                        if ("OMX.IMG.MSVDX.Decoder.AVC".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omximgmsvdxdecoderavc";
                            return decoder;
                        }
                        //猎户座Exynos VIVO X30,VIVO S6
                        if ("OMX.Exynos.AVC.Decoder".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxexynosavcdecoder";
                            return decoder;
                        }
                        //猎户座上一代 三星GALAXY S6 Edge+
                        if ("OMX.Exynos.avc.dec".equals(codecInfo.getName())) {
                            decoder = "! parsebin ! amcviddec-omxexynosavcdec";
                            return decoder;
                        }
                    }
                }
            }
            return softDecoder;
        } catch (Exception e) {
            e.printStackTrace();
            return softDecoder;
        }
    }

    /**
     * RTP包分离H265码流
     * https://blog.51cto.com/fengyuzaitu/2925973
     *
     * @param pData       源数据
     * @param pDataLength 源数据长度
     * @param dData       结果数据
     * @return 结果数据长度
     */
    public static int readH265FromRTP(byte[] pData, int pDataLength, byte dData[]) {
        //RTP头12个字节，H265 NALU单元需要两个字节，对于FUs模式的RTP,还需要多一个字节保存FUs分包类型
        if (pDataLength < 15)
            return 0;
        //打印RTP报文
        //LogUtil.d(TAG, ByteUtil.bytesToHexWithSpace(pData, 0, pDataLength));
        //RTP头解析
        int rtpSn = ByteUtil.bytesToUint16(pData, 2, false);//序列号，占16位，发送方在每发送完一个RTP包后就将该域的值增加1，接收方可以由该域检测包的丢失及恢复包序列。序列号的初始值是随机的。
        long rtpTimeStamp = ByteUtil.bytesToUint32(pData, 4, false);//时间戳，占32位，记录了该包中数据的第一个字节的采样时刻。它是去除抖动和实现同步不可缺少的。
        //LogUtil.d("VideoTCP", "RTP序列号：" + num + " 时间戳：" + timeStamp, false);
        if ((rtpSn - RtpSnLast) == 1) {
        } else {
            LogUtil.d("RTP序列号：" + rtpSn + " 旧的序列号：" + RtpSnLast);
        }
        RtpSnLast = rtpSn;

        //H265头解析
        //获取FU-A分片的第一个字节的中间六位，判断分片类型。是否FU包
        int cFragmentationUnitType = (pData[12] & 0x7E) >> 1;
        //LogUtil.d("VideoUDP", "帧类型：" + cFragmentationUnitType, false);
        switch (cFragmentationUnitType) {
            case 48://AP包，一个RTP包含有N(N>=2)个NALU TODO 暂不处理
                return 0;
            case 49://FU包,几个RTP包拼接成一个NALU
                //获取FU Header分片的最后六位，判断当前的帧类型
                //int cFrameType = pData[14] & 0x3F;//实际帧类型
                int cStartBit = (pData[14] & 0xFF) >> 7;//第一片标识
                //int cEndBit = (pData[14] & 0x40) >> 6;//最后一片标识
                //LogUtil.d("VideoUDP", "实际帧类型：" + cFrameType + "第一片标识：" + cStartBit + "最后一片标识：" + cEndBit, false);
                if (cStartBit == 1) {
                    ///根据FUs头第一个字节 和 FU Header 拼凑出NAL头部
                    // ((pData[14] & 0x3F) << 1取FU Header的最后六位，并且移动到中间
                    //pData[12] & 0x81)Fus第一个字节的中间六位置零，进行或操作
                    byte cNALHeader = (byte) ((pData[12] & 0x81) | ((pData[14] & 0x3F) << 1));
                    System.arraycopy(NALUStartCode, 0, dData, 0, NALUStartCode.length);
                    dData[NALUStartCode.length] = cNALHeader;
                    dData[NALUStartCode.length + 1] = pData[13];
                    System.arraycopy(pData, 15, dData, NALUStartCode.length + 2, pDataLength - 15);
                    return NALUStartCode.length + 2 + pDataLength - 15;
                } else {
                    System.arraycopy(pData, 15, dData, 0, pDataLength - 15);
                    return pDataLength - 15;
                }
            /*case 1://非IDR帧，长度小于MTU单元
            case 32://视频参数集VPS
            case 33://序列参数集SPS
            case 34://序列参数集PPS
            case 39://补充增强信息SEI*/
            default:
                //一般情况下都是单独完整的一个RTP包，直接去掉RTP头部
                System.arraycopy(NALUStartCode, 0, dData, 0, NALUStartCode.length);
                System.arraycopy(pData, 12, dData, NALUStartCode.length, pDataLength - 12);
                return NALUStartCode.length + pDataLength - 12;
        }
    }
}
